package cn.edu.xjtu.carlWay.tree.countCompleteTreeNode;

import cn.edu.xjtu.Util.TreeNode.TreeNode;

import java.util.Deque;
import java.util.LinkedList;

/**
 * 222. 完全二叉树的节点个数
 * 给你一棵 完全二叉树 的根节点 root ，求出该树的节点个数。
 * <p>
 * 完全二叉树 的定义如下：在完全二叉树中，除了最底层节点可能没填满外，其余每层节点数都达到最大值，并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层，则该层包含 1~ 2^h 个节点。
 * <p>
 * https://leetcode-cn.com/problems/count-complete-tree-nodes/
 */
public class Solution {

    /**
     * 直接递归版本,没有利用到完全二叉树的特性
     *
     * @param root
     * @return
     */
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }

        return countNodes(root.left) + countNodes(root.right) + 1;
    }

    /**
     * 迭代版本,没有利用到完全二叉树的特性
     *
     * @param root
     * @return
     */
    public int countNodes1(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int nodeNum = 0;
        Deque<TreeNode> deque = new LinkedList<>();
        deque.addLast(root);
        while (!deque.isEmpty()) {
            nodeNum++;
            TreeNode node = deque.removeFirst();
            if (node.left != null) {
                deque.addLast(node.left);
            }
            if (node.right != null) {
                deque.addLast(node.right);
            }
        }

        return nodeNum;
    }

    /**
     * 递归版本,利用完全二叉树的特性进行计算
     *
     * @param root
     * @return
     */
    public int countNodes2(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = 1;
        int rightDepth = 1;
        TreeNode leftNode = root.left;
        TreeNode rightNode = root.right;
        while (leftNode != null) {
            leftDepth++;
            leftNode = leftNode.left;
        }
        while (rightNode != null) {
            rightDepth++;
            rightNode = rightNode.right;
        }
        if (leftDepth == rightDepth) {
            return (int) Math.pow(2, leftDepth) - 1;
        }
        return countNodes2(root.left) + countNodes2(root.right) + 1;
    }
}
